home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 076-100 / 079 / monproc / monproc.c < prev    next >
C/C++ Source or Header  |  1995-03-13  |  10KB  |  376 lines

  1. /*
  2.  *  MONPROC.C    - Monitor AmigaDOS process packet activity.
  3.  *
  4.  *        Phillip Lindsay (c) 1987 Commodore-Amiga, Inc.
  5.  *  You may use this source as long as this copywrite notice is left intact.
  6.  *
  7.  *  re-organized and slightly re-worked by Davide P. Cervone, 4/25/87.
  8.  */
  9.  
  10. #include <exec/types.h>
  11. #include <exec/ports.h>
  12. #include <exec/semaphores.h>
  13. #include <libraries/dos.h>
  14. #include <libraries/dosextens.h>
  15. #include <stdio.h>
  16.  
  17. #ifdef MANX
  18. #include <functions.h>
  19. #endif
  20.  
  21. #define ONE         1L
  22.  
  23. /*
  24.  * AmigaDOS uses task signal bit 8 for message signaling
  25.  */
  26.  
  27. #define DOS_SIGNAL   8
  28. #define DOS_MASK     (ONE<<DOS_SIGNAL)
  29.  
  30. #define PTR(x,p)     ((struct x *)(p))
  31.  
  32. extern void GetProcList(),FreeProcList(),PrintPkt();
  33. extern LONG AllocSignal(), Wait();
  34. extern struct Message *PacketWait(), *GetMsg();
  35. extern struct Process *FindTask();
  36. extern struct DosLibrary *DOSBase;
  37. extern int Dump_OK, Lock_OK;
  38.  
  39.  
  40. struct MsgPort         *thePort;        /* the port we will be monitoring */
  41. struct Process         *myProcess;      /* pointer to our own process */
  42. ULONG                  WaitMask;        /* the task signal mask */
  43. struct SignalSemaphore CanReturn = {0}; /* coordinates PacketWait */
  44. struct Message         *theMessage;     /* the message we received */
  45. APTR                   OldPktWait;      /* the old pr_PktWait routine */
  46.  
  47.  
  48. #ifdef MANX
  49.    LONG PWait();        /* this is the ASM stub that calls PacketWait() */
  50. #else
  51.    #define PWait   PacketWait
  52. #endif
  53.  
  54. #ifndef MANX
  55.    Ctrl_C()             /* Control-C Trap routine for Lattice */
  56.    {
  57.       return(0);
  58.    }
  59. #endif
  60.  
  61.  
  62. /*
  63.  *  PacketWait()
  64.  *
  65.  *  This is the routine placed in the pr_PktWait field of the monitored
  66.  *  precess.  It is run asynchronously by the monitored process, and is
  67.  *  called whenever AmigaDOS does a taskwait().  PacketWait() waits for
  68.  *  a message to come in and then signals the monitoring task that one has
  69.  *  arrived.  It then attempts to obtain the semaphore, which will not be
  70.  *  released by the monitoring process until it is finished printing the 
  71.  *  contents of the packet.
  72.  */
  73.  
  74. struct Message *PacketWait()
  75. {
  76. #ifdef MANX
  77.    /*
  78.     *  if MANX, make sure we can see our data
  79.     */
  80.    geta4();
  81. #endif
  82.  
  83.    SetSignal(FALSE,DOS_MASK);
  84.  
  85.    while(!(theMessage = GetMsg(thePort)))  Wait(DOS_MASK);
  86.  
  87.    Signal(myProcess,WaitMask);
  88.    ObtainSemaphore(&CanReturn);
  89.    ReleaseSemaphore(&CanReturn);
  90.  
  91.    return(theMessage);
  92.  
  93.  
  94. /*
  95.  *  DoArguments()
  96.  *
  97.  *  Parses the command line to make sure it contains only valid arguments,
  98.  *  and sets the flag variables to their proper values (they are initialized
  99.  *  in printpkt.c).  The legal options are:
  100.  *
  101.  *      [NO]DUMP        To control hex dumps of long buffers
  102.  *      [NO]LOCK        To control the display of LOCK parameters
  103.  *                      (you should use NOLOCK if you are monitoring a
  104.  *                      file system process).
  105.  */
  106.  
  107. void DoArguments(argc,argv)
  108. int argc;
  109. char **argv;
  110. {
  111.    while (--argc)
  112.    {
  113.       argv++;
  114.       if (stricmp(*argv,"NODUMP") == 0)      Dump_OK = FALSE;
  115.       else if (stricmp(*argv,"DUMP") == 0)   Dump_OK = TRUE;
  116.       else if (stricmp(*argv,"NOLOCK") == 0) Lock_OK = FALSE;
  117.       else if (stricmp(*argv,"LOCK") == 0)   Lock_OK = TRUE;
  118.       else
  119.       {
  120.          printf("Bad Argument:  '%s'\n",*argv);
  121.          printf("Usage:  MONPROC [NO]DUMP [NO]LOCK\n");
  122.          exit(5);
  123.       }
  124.    }
  125. }
  126.  
  127.  
  128. /*
  129.  *  GetProcToMonitor()
  130.  *
  131.  *  Lists the processes currently running and lets the user choose one.
  132.  *  Returns a pointer the the chosen process.
  133.  */
  134.  
  135. struct Process *GetProcToMonitor()
  136. {
  137.    struct List           ProcList;
  138.    struct Node           *theProc;
  139.    struct Process        *ChosenProcess = NULL;
  140.    ULONG                 count,choice;
  141.    char                  s[80];
  142.  
  143. /*
  144.  *  Set up ProcList and a list header and read the process list into it
  145.  *  (we assume the process list won't change).
  146.  */
  147.    NewList(&ProcList);
  148.    GetProcList(&ProcList);
  149.  
  150. /*
  151.  *  If there are any processes, list them and let the user chose one by 
  152.  *  number.  If he choses a legal number, find the process in the list
  153.  *  and return a pointer to the process structure for that process.
  154.  *  Finally, free the process list.
  155.  */
  156.    if (ProcList.lh_TailPred == PTR(Node,&ProcList))
  157.    {
  158.       printf("No Processes.\n");
  159.    } else {
  160.       do
  161.       {
  162.          printf("\nEnter NUMBER for process to monitor:\n"); 
  163.          printf("Pick# Process  MsgPort  Name\n");    
  164.          for (count=1,theProc=ProcList.lh_Head;    /* start at the list head */
  165.               theProc->ln_Succ;                    /* while there are more */
  166.               theProc=theProc->ln_Succ,count++)    /* go on to the next */
  167.          {
  168.             printf("%4ld. %08lX %08lX %s\n",count,
  169.                theProc->ln_Name,
  170.                &(PTR(Process,theProc->ln_Name)->pr_MsgPort),
  171.                PTR(Process,theProc->ln_Name)->pr_Task.tc_Node.ln_Name);
  172.          }
  173.          printf("\nNUMBER: ");
  174.          gets(s);
  175.       } while (sscanf(s,"%ld",&choice) != 1);
  176.   
  177.       if (choice < 1 || choice >= count)
  178.       {
  179.          printf("Operation Aborted.\n");
  180.       } else {
  181.          for (count=1,theProc=ProcList.lh_Head;
  182.               count < choice;
  183.               theProc=theProc->ln_Succ,count++);
  184.          ChosenProcess = PTR(Process,theProc->ln_Name);
  185.       }
  186.       FreeProcList(&ProcList);
  187.    }
  188.    return(ChosenProcess);
  189. }
  190.  
  191.  
  192. /*
  193.  *  SetupSignal()
  194.  *
  195.  *  Allocate a signal to use for our inter-task communication, and
  196.  *  set up the mask for using it.
  197.  */
  198.  
  199. void SetupSignal(theSignal)
  200. LONG *theSignal;
  201. {
  202.    *theSignal = AllocSignal(-ONE);
  203.    if (*theSignal == -ONE)
  204.    {
  205.       printf("Can't Allocate a Task Signal.");
  206.       exit(10);
  207.    }
  208.    WaitMask = (ONE << (*theSignal));
  209. }
  210.  
  211.  
  212. /*
  213.  *  SetupProcess()
  214.  *
  215.  *  Copy the process name, and gets it Message port.  Set our priority
  216.  *  higher than the monitored process so we will be able to react to its
  217.  *  signals.  Then set the pr_PktWait field so that we begin monitoring 
  218.  *  the other task.  Save the old one so we can put it back.
  219.  */
  220.  
  221. void SetupProcess(theProcess,name)
  222. struct Process *theProcess;
  223. char *name;
  224. {
  225.    strcpy(name,theProcess->pr_Task.tc_Node.ln_Name);
  226.    thePort = &theProcess->pr_MsgPort;
  227.  
  228.    Forbid();
  229.    SetTaskPri(myProcess,(ULONG)(theProcess->pr_Task.tc_Node.ln_Pri + 1)); 
  230.    OldPktWait = theProcess->pr_PktWait;
  231.    theProcess->pr_PktWait = (APTR) PWait;
  232.    Permit();
  233. }
  234.  
  235.  
  236. /*
  237.  *  MonitorProcess()
  238.  *
  239.  *  Wait for the monitored process to receive a message (our PacketWait()
  240.  *  function signals us via theSignal when it has received a message), then
  241.  *  print out the contents of the message.  A semaphore is used to coordinate
  242.  *  this routine with the PacketWait() routine (which is run asynchonously
  243.  *  by the monitored process).  Phillip Lindsay says "there are probably a
  244.  *  hundred better was of doing this.  I just went with the first one [that]
  245.  *  came to mind."  I couldn't think of a better one, so I still use it.
  246.  *  Since our process is running at a higher priority than the monitored one,
  247.  *  we should obtain the semaphore first.  The other process wil block until
  248.  *  we release it (when we are done printing the contents).
  249.  */
  250.  
  251. void MonitorProcess(name,theSignal)
  252. char *name;
  253. ULONG theSignal;
  254. {
  255.    ULONG                signals;
  256.    struct DosPacket     *thePacket;
  257.  
  258.    do 
  259.    {
  260.       signals = Wait(SIGBREAKF_CTRL_C | WaitMask); 
  261.       ObtainSemaphore(&CanReturn); 
  262.       if (signals & WaitMask)
  263.       {
  264.          /*
  265.           *  PacketWait() signalled us so print the message it put in
  266.           *  theMessage.
  267.           */
  268.          thePacket = PTR(DosPacket,theMessage->mn_Node.ln_Name);
  269.          printf("\n%s: ",name);     
  270.          PrintPkt(thePacket);
  271.       }
  272.       ReleaseSemaphore(&CanReturn);
  273.    } while(!(signals & SIGBREAKF_CTRL_C)); 
  274. }
  275.  
  276.  
  277. /*
  278.  *  ClenUpProcess()
  279.  *
  280.  *  Put everything back the way we found it, except that the monitored process
  281.  *  is still running our code...
  282.  */
  283.  
  284. void CleanUpProcess(theProcess)
  285. struct Process *theProcess;
  286. {
  287.    Forbid();
  288.    theProcess->pr_PktWait = OldPktWait;
  289.    Permit();
  290.    SetTaskPri(myProcess,0L);
  291. }
  292.  
  293.  
  294. /*
  295.  *  WaitForLastPacket()
  296.  *
  297.  *  Since the monitored process is still running our PacketWait() code, we
  298.  *  can't quit yet.  Since we already put back the old pr_PktWait pointer,
  299.  *  our code will not be called after the next packet is received, so we have
  300.  *  to wait for one more packet before we can quit.  Note that PacketWait()
  301.  *  will still signal us, so we know when it will be safe to remove the code.
  302.  *  Just in case we goof, let CTRL-E cancel, too.
  303.  */
  304.  
  305. void WaitForLastPacket(theSignal)
  306. ULONG theSignal;
  307. {
  308.    ULONG signals;
  309.  
  310.    printf("\nThe process must receive another message before we can safely\n");
  311.    printf("remove the packet wait code.  We will wait for one more packet.\n");
  312.    printf("Press CTRL-E if you want to quit early, but that will likely\n");
  313.    printf("crash the monitored process!\n");
  314.  
  315.    signals = Wait(SIGBREAKF_CTRL_E | WaitMask);
  316.    if (signals & WaitMask)
  317.    {
  318.       ObtainSemaphore(&CanReturn);
  319.       ReleaseSemaphore(&CanReturn);
  320.    }
  321. }
  322.  
  323. void main(argc,argv)
  324. int argc;
  325. char **argv;
  326. {
  327.    struct Process    *ChosenProcess;
  328.    LONG              TaskSignal;
  329.    UBYTE             ProcessName[81];
  330.    
  331.    if (argc > 1) DoArguments(argc,argv);
  332.  
  333.    printf("\n%s - monitor AmigaDOS process packet activity.\n",*argv);
  334.  
  335.    myProcess = FindTask(NULL);
  336.    ChosenProcess = GetProcToMonitor();
  337.    if (ChosenProcess != NULL)
  338.    {
  339.       #ifndef MANX
  340.          onbreak(&Ctrl_C);    /* Turn off CTRL-C for Lattice:  we do our own */
  341.       #endif
  342.  
  343.       SetupSignal(&TaskSignal);
  344.       InitSemaphore(&CanReturn);
  345.       SetupProcess(ChosenProcess,ProcessName);
  346.       printf("Monitor Installed, press CTRL-C to quit monitoring\n"); 
  347.    
  348.       MonitorProcess(ProcessName,TaskSignal);
  349.       
  350.       CleanUpProcess(ChosenProcess);
  351.       WaitForLastPacket(TaskSignal);
  352.       FreeSignal(TaskSignal);
  353.  
  354.       printf("\nAll done.\n");
  355.    }
  356. }
  357.  
  358.  
  359. /*
  360.  *  This code stub has been known to save lives... 
  361.  */
  362.  
  363. #if MANX        
  364. #asm
  365.         XREF _PacketWait
  366.  
  367.         XDEF _PWait
  368. _PWait:
  369.         movem.l a2/a3/a4,-(sp)
  370.         jsr _PacketWait
  371.         movem.l (sp)+,a2/a3/a4
  372.         rts
  373. #endasm
  374. #endif
  375.